package com.apes.framework.util.monitor;

import com.alibaba.druid.support.monitor.annotation.AggregateType;
import com.alibaba.druid.support.monitor.annotation.MField;
import com.apes.framework.util.LogicalUtil;
import com.apes.framework.util.ReflectUtil;

import java.beans.PropertyDescriptor;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Date;

public class MonitorUtil {

    public static void copyAll(Object source, Object target, String... excludes) {
        PropertyDescriptor[] propertyDescriptors = ReflectUtil.getPropertyDescriptors(target);
        Arrays.stream(propertyDescriptors).filter(property -> LogicalUtil.notIn(property.getName(), excludes)).forEach(property -> {
            String fieldName = property.getName();
            Object nv = ReflectUtil.getFieldValue(source, fieldName);
            if (nv == null) return;
            if (nv.getClass().isAssignableFrom(Date.class)) {
                nv = ((Date) nv).getTime();
            }
            Object v = nv;
            MField mField = ReflectUtil.getAnnotation(target, fieldName, MField.class);
            if (mField != null) {
                Object ov = ReflectUtil.getFieldValue(target, property);
                AggregateType aggregateType = mField.aggregate();
                if ((ov != null) && (ov instanceof Number && nv instanceof Number) &&
                        (aggregateType == AggregateType.Sum || aggregateType == AggregateType.Max)) {
                    BigDecimal a = new BigDecimal(String.valueOf(ov));
                    BigDecimal b = new BigDecimal(String.valueOf(nv));
                    BigDecimal result;
                    if (aggregateType == AggregateType.Sum) {
                        result = a.add(b);
                    } else {
                        result = a.max(b);
                    }
                    if (ov instanceof Integer) {
                        v = result.intValue();
                    } else if (ov instanceof Double) {
                        v = result.doubleValue();
                    } else if (ov instanceof Float) {
                        v = result.floatValue();
                    } else {
                        v = result.longValue();
                    }
                }
            }
            ReflectUtil.setField(target, property, v);
        });
    }

}
